/**
 *Manager usage of vm mapped to /dev/mem 0x1000000~0x1dfffff
 *When create a MemPool, it's pool_ should be alloc use this class.
 *It will first alloc firstly try to alloc from memory map to /dev/mem.
 *If there is not enough memory in /dev/mem 0x1000000~0x1dfffff, it
 *will try to call calloc() func of stdlib to alloc memory.
 */

#ifndef UTILS_MEM_ALLOCATOR_C_H_
#define UTILS_MEM_ALLOCATOR_C_H_

#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <stddef.h>

#define MEM_ALLOC_DEFAULT 1
#define MEM_ALLOC_MAP 1
#define MEM_FD_INIT -1

//=====================================================================
// MemMapMemAllocator
// Use MemMap to map /dev/mem 0x1000000-0x1dffefff into virtual memory.
// Use a linked table to store ranges in this mapping space. A range
// may be free or in-use.
//=====================================================================

typedef struct MemAllocator MemAllocator;
typedef struct MemRange MemRange;
typedef struct MMapParams MMapParams;
typedef struct MemAllocDelegate MemAllocDelegate;

#define MMAP_BASE_ADDR 0x10000000
#define MMAP_HIGH_ADDR 0x1DFFEFFF

struct MemRange {
  int8_t* offset;
  int8_t* end;
  uint32_t size;
  bool is_dirty;
  MemRange* next;
  MemRange* pre;
};

struct MMapParams {
  MemRange* range_list;
  int32_t mem_fd;
  int8_t* map_base;
  uint32_t page_size;
  uint32_t base_addr;
  uint32_t high_addr;
};

struct MemAllocator {
  int8_t* (*calloc)(MemAllocator* allocator, uint32_t nmemb, uint32_t size);
  void (*free)(MemAllocator* allocator, int8_t* buffer);
  char allocator_name[32];
  MMapParams* mmap_params;
  MemAllocator* next;
};

struct MemAllocDelegate{
  MemAllocator* allocator;
};

void init_mem_delegate(MemAllocDelegate* delegate, uint32_t base_addr, uint32_t high_addr);
int8_t* mem_delegate_calloc(MemAllocDelegate* delegate, uint32_t nmemb, uint32_t size);
void mem_delegate_free(MemAllocDelegate* delegate, int8_t* buffer);
void destroy_mem_delegate(MemAllocDelegate* delegate);

#endif  // UTILS_MEM_ALLOCATOR_C_H_
